package data

import (
	"encoding/json"
	"log"
	"strings"
	"sync"
	"time"
	"webProxy/pkg/utils"
)

var (
	// Subscriberinfo 全局广播
	Subscriberinfo map[string]*SubscriberHandler // clientId->handler
	locker         sync.RWMutex
	// SubscriberinfoV2 分端口广播
	SubscriberinfoV2 map[int64]map[string]*SubscriberHandler // port->clientId->handler
	lockerV2         sync.RWMutex
)

// MsgInfo 消息体结构
type MsgInfo struct {
	Path           string            `json:"path"`
	Query          string            `json:"query"`
	Url            string            `json:"url"`
	Host           string            `json:"host"`
	Method         string            `json:"method"`
	Status         int64             `json:"status"`
	RequestContent string            `json:"requestContent"`
	RespContent    string            `json:"respContent"`
	Headers        map[string]string `json:"headers"`
	Scheme         string            `json:"scheme"`
	RecvTime       time.Time         `json:"-"`
}

// SubscriberHandler 请求监听消息handler
type SubscriberHandler struct {
	RemoteAddr string
	UUId       string
	MsgChan    chan *MsgInfo
	PathFilter []string
}

func AddSubscriber(handler *SubscriberHandler) {
	locker.Lock()
	defer locker.Unlock()
	log.Printf("AddSubscriber info, remoteAddr:%s, uuID:%s, time:%s\n", handler.RemoteAddr, handler.UUId, time.Now().String())
	Subscriberinfo[handler.UUId] = handler
}

func RemSubscriber(uuId string) {
	locker.Lock()
	defer locker.Unlock()
	if h, ok := Subscriberinfo[uuId]; ok {
		log.Printf("RemSubscriber info, remoteAddr:%s, uuID:%s, time:%s\n", h.RemoteAddr, uuId, time.Now().String())
		delete(Subscriberinfo, uuId)
	}
}

func AddSubscriberV2(handler *SubscriberHandler, port int64) {
	lockerV2.Lock()
	defer lockerV2.Unlock()

	log.Printf("AddSubscriberV2 info, remoteAddr:%s, uuID:%s, time:%s\n", handler.RemoteAddr, handler.UUId, time.Now().String())
	if cli, ok := SubscriberinfoV2[port]; !ok {
		cliTmp := make(map[string]*SubscriberHandler)
		cliTmp[handler.UUId] = handler
		SubscriberinfoV2[port] = cliTmp
	} else {
		cli[handler.UUId] = handler
	}
}

func RemSubscriberV2(uuId string, port int64) {
	lockerV2.Lock()
	defer lockerV2.Unlock()

	if cli, ok := SubscriberinfoV2[port]; ok {
		if h, ok := cli[uuId]; ok {
			log.Printf("RemSubscriberV2 info, remoteAddr:%s, uuID:%s, time:%s\n", h.RemoteAddr, uuId, time.Now().String())
			delete(cli, uuId)
		}
	}
}

// broadMsg 广播消息
func broadMsg(msg string, port int64) {
	msgObj := &MsgInfo{
		RecvTime: time.Now(),
	}
	if err := json.Unmarshal([]byte(msg), msgObj); err != nil {
		log.Printf("broadMsg json.Unmarshal fail, data:%s, err:%s\n", msg, err.Error())
		return
	}

	if port == 0 {
		broadAll(msgObj)
		return
	}

	broadByPort(msgObj, port)
}

// broadAll 广播全局, v1接口
func broadAll(msg *MsgInfo) {
	locker.RLock()
	defer locker.RUnlock()

	uuIDs := make([]string, 0)

	for _, tmp := range Subscriberinfo {
		tmpObj := tmp
		uuIDs = append(uuIDs, tmp.UUId)
		utils.SafeGoFunc(
			func() {
				select {
				case tmpObj.MsgChan <- msg:
				default:
				}
			})
	}

	log.Printf("broadAll clients, url:%s, uuIDs:%+v, time:%s\n", msg.Url, uuIDs, time.Now().String())
}

// broadByPort 区分端口广播
func broadByPort(msg *MsgInfo, port int64) {
	lockerV2.RLock()
	defer lockerV2.RUnlock()

	log.Printf("broadByPort clients, port:%d, msg:%+v, time:%s\n", port, msg, time.Now().String())

	if cli, ok := SubscriberinfoV2[port]; ok {
		if cli == nil {
			return
		}

		for _, cliTmp := range cli {
			// 检查路径过滤
			if len(cliTmp.PathFilter) == 0 {
				// 没有进行过滤
				utils.SafeGoFunc(
					func() {
						select {
						case cliTmp.MsgChan <- msg:
						default:
						}
					})
				continue
			}

			for _, pathTmp := range cliTmp.PathFilter {
				if ok := strings.Contains(msg.Path, pathTmp); ok {
					utils.SafeGoFunc(
						func() {
							select {
							case cliTmp.MsgChan <- msg:
							default:
							}
						})
					continue
				}
			}
		}
	}
}
